package com.introspy.hooks; import java.io.File; import java.net.InetAddress; import java.net.Socket; import java.net.URI; import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.Key; import java.security.KeyStore; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Set; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.TrustManager; import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.params.HttpParams; import com.introspy.core.HookConfig; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentValues; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.os.Handler; public class HookList { static public HookConfig[] getHookList() { return _hookList; } static private HookConfig[] _hookList = new HookConfig[] { /* ############################################ * ############### Crypto Methods */ new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "getInstance", new Intro_CRYPTO(), new Class<?>[]{String.class}, ""), new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "update", new Intro_CRYPTO(), new Class<?>[]{byte[].class}, "Continues a multi-part transformation (encryption or decryption)"), new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "update", new Intro_CRYPTO(), new Class<?>[]{byte[].class}, "Continues a multi-part transformation (encryption or decryption)"), new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "java.util.Random", "Random", new Intro_SHOULD_NOT_BE_USED(), new Class<?>[]{}, "Weak RNG"), // doesn't need to hook that if you hook doFinal as the hook calls it already new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "getIV", new Intro_CRYPTO(), new Class<?>[]{}, ""), // this gives the hash algo + hash // need to hook "update" to get what is hashed // we can also retrieve this info by hooking 'update' // so I'm disabling it new HookConfig(false, "CRYPTO", "HASH", "java.security.MessageDigest", "digest", new Intro_GET_HASH(), new Class<?>[]{}, ""), // ############ doFinal new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{}, "Finishes a multi-part transformation (encryption or decryption)"), // method doesn't seem to exist in Android < 4 new HookConfig(false, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{byte[].class, Integer.TYPE}, "Finishes a multi-part transformation (encryption or decryption)"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{byte[].class, Integer.TYPE, Integer.TYPE}, "Finishes a multi-part transformation (encryption or decryption)"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{byte[].class, Integer.TYPE, Integer.TYPE, byte[].class, Integer.TYPE}, "Finishes a multi-part transformation (encryption or decryption)"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{byte[].class, Integer.TYPE, Integer.TYPE, byte[].class}, "Finishes a multi-part transformation (encryption or decryption)"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{ByteBuffer.class, ByteBuffer.class}, "Finishes a multi-part transformation (encryption or decryption)"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "doFinal", new Intro_CRYPTO_FINAL(), new Class<?>[]{byte[].class}, "Finishes a multi-part transformation (encryption or decryption)"), // ########### Key related functions new HookConfig(true, "CRYPTO", "KEY", "javax.crypto.spec.PBEKeySpec", "PBEKeySpec", new Intro_CRYPTO_PBEKEY(), new Class<?>[]{char[].class, byte[].class, Integer.TYPE, Integer.TYPE}, "Create a key with: pwd, salt, iterations, keylength"), new HookConfig(true, "CRYPTO", "KEY", "javax.crypto.spec.PBEKeySpec", "PBEKeySpec", new Intro_CRYPTO_PBEKEY(), new Class<?>[]{char[].class, byte[].class, Integer.TYPE}, "Create a key with: pwd, salt, iterations"), new HookConfig(true, "CRYPTO", "KEY", "javax.crypto.spec.PBEKeySpec", "PBEKeySpec", new Intro_CRYPTO_PBEKEY(), new Class<?>[]{char[].class}, "Create a key with: pwd"), new HookConfig(true, "CRYPTO", "KEY", "javax.crypto.spec.SecretKeySpec", "SecretKeySpec", new Intro_GET_KEY(), new Class<?>[]{byte[].class, String.class}, ""), // keystore - get the cert and the .p12 passcode new HookConfig(true, "CRYPTO", "KEY", "org.apache.http.conn.ssl.SSLSocketFactory", "SSLSocketFactory", new Intro_CRYPTO_KEYSTORE_HOSTNAME(), new Class<?>[]{String.class, KeyStore.class, String.class, KeyStore.class, SecureRandom.class, HostNameResolver.class}, ""), new HookConfig(true, "CRYPTO", "KEY", "org.apache.http.conn.ssl.SSLSocketFactory", "SSLSocketFactory", new Intro_CRYPTO_KEYSTORE(), new Class<?>[]{KeyStore.class, String.class, KeyStore.class}, ""), new HookConfig(true, "CRYPTO", "KEY", "org.apache.http.conn.ssl.SSLSocketFactory", "SSLSocketFactory", new Intro_CRYPTO_KEYSTORE(), new Class<?>[]{KeyStore.class, String.class}, ""), //new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "org.apache.http.conn.ssl.SSLSocketFactory", "SSLSocketFactory", // new Intro_CRYPTO_KEYSTORE(), new Class<?>[]{KeyStore.class}, ""), // ############ digest (hash function) // may not need to call the digest methods when update is hooked (?) new HookConfig(false, "CRYPTO", "HASH", "java.security.MessageDigest", "digest", new Intro_HASH(), new Class<?>[]{byte[].class, Integer.TYPE, Integer.TYPE}, "Performs the final update and then computes and returns the final hash value"), new HookConfig(false, "CRYPTO", "HASH", "java.security.MessageDigest", "digest", new Intro_HASH(), new Class<?>[]{byte[].class}, "Performs the final update and then computes and returns the final hash value"), new HookConfig(true, "CRYPTO", "HASH", "java.security.MessageDigest", "update", new Intro_HASH(), new Class<?>[]{byte[].class}, "Uses a one-way hash function to turn an arbitrary number of " + "bytes into a fixed-length byte sequence."), new HookConfig(true, "CRYPTO", "HASH", "java.security.MessageDigest", "update", new Intro_HASH(), new Class<?>[]{byte[].class, Integer.TYPE, Integer.TYPE}, "Uses a one-way hash function to turn an arbitrary number of " + "bytes into a fixed-length byte sequence."), new HookConfig(true, "CRYPTO", "HASH", "java.security.MessageDigest", "update", new Intro_HASH(), new Class<?>[]{ByteBuffer.class}, "Uses a one-way hash function to turn an arbitrary number of " + "bytes into a fixed-length byte sequence."), // ############ init new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class}, "Initializes this cipher instance with the specified key"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class, SecureRandom.class}, "Initializes this cipher instance with the specified key"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class, AlgorithmParameterSpec.class, SecureRandom.class}, "Initializes this cipher instance with the specified key"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class, AlgorithmParameters.class, SecureRandom.class}, "Initializes this cipher instance with the specified key"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class, AlgorithmParameters.class}, "Initializes this cipher instance with the specified key"), new HookConfig(true, "CRYPTO", "GENERAL CRYPTO", "javax.crypto.Cipher", "init", new Intro_CRYPTO_INIT(), new Class<?>[]{Integer.TYPE, Key.class, AlgorithmParameterSpec.class}, "Initializes this cipher instance with the specified key"), // TODO: 3 init calls missing (with certificates) /* ############################################ * ############### File System Methods */ new HookConfig(true, "STORAGE", "FS", "java.io.FileOutputStream", "FileOutputStream", new Intro_FILE_CHECK_DIR(), new Class<?>[]{File.class}, ""), // crashes new HookConfig(false, "STORAGE", "FS", "java.io.File", "File", new Intro_FILE_CHECK_DIR(), new Class<?>[]{String.class}, ""), // does not always work when other FS APIs are hooked (crashes) new HookConfig(false, "STORAGE", "FS", "java.io.File", "File", new Intro_FILE_CHECK_DIR(), new Class<?>[]{String.class, String.class}, ""), // URI new HookConfig(true, "STORAGE", "FS", "java.io.File", "File", new Intro_DUMP(), new Class<?>[]{URI.class}, ""), // bad: true, false: (boolean readable, boolean ownerOnly) new HookConfig(true, "STORAGE", "FS", "java.io.File", "setReadable", new Intro_CHECK_FS_SET(), new Class<?>[]{Boolean.TYPE, Boolean.TYPE}, "Manipulates the read permissions for the abstract path designated by this file."), new HookConfig(true, "STORAGE", "FS", "java.io.File", "setWritable", new Intro_CHECK_FS_SET(), new Class<?>[]{Boolean.TYPE, Boolean.TYPE}, "Manipulates the read permissions for the abstract path designated by this file."), new HookConfig(true, "STORAGE", "FS", "java.io.File", "setExecutable", new Intro_CHECK_FS_SET(), new Class<?>[]{Boolean.TYPE, Boolean.TYPE}, "Manipulates the read permissions for the abstract path designated by this file."), // secu, world/readable new HookConfig(true, "STORAGE", "FS", "android.content.ContextWrapper", "openFileOutput", new Intro_FILE_CHECK_MODE(), new Class<?>[]{String.class, Integer.TYPE}, ""), /* ############################################ * ############### IPC Methods */ new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "startService", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class}, ""), new HookConfig(false, "IPC", "IPC", "android.content.ContextWrapper", "startActivities", new Intro_DUMP_INTENT(), new Class<?>[]{Intent[].class}, ""), // Android > 4.1 new HookConfig(false, "IPC", "IPC", "android.content.ContextWrapper", "startActivity", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class, Bundle.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "startActivity", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class, Bundle.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "startActivity", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "startActivity", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "sendBroadcast", new Intro_DUMP_INTENT(), new Class<?>[]{Intent.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "sendBroadcast", new Intro_DUMP(), new Class<?>[]{Intent.class, String.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "registerReceiver", new Intro_IPC_RECEIVER(), new Class<?>[]{BroadcastReceiver.class, IntentFilter.class}, ""), new HookConfig(true, "IPC", "IPC", "android.content.ContextWrapper", "registerReceiver", new Intro_IPC_RECEIVER(), new Class<?>[]{BroadcastReceiver.class, IntentFilter.class, String.class, Handler.class}, ""), // TODO: more IPCs to hook here, sendBroadcast(s) for instance // useful to find dynamically enabled IPCs // crashes the zygote process on 4.2.2 (?) new HookConfig(false, "IPC", "IPC", "android.content.pm.PackageManager", "setComponentEnabledSetting", new Intro_IPC_MODIFIED(), new Class<?>[]{ComponentName.class, Integer.TYPE, Integer.TYPE}, ""), /* ############################################ * ############### Shared Preference Methods */ new HookConfig(true, "STORAGE", "PREF", "android.content.ContextWrapper", "getSharedPreferences", new Intro_CHECK_SHARED_PREF(), new Class<?>[]{String.class, Integer.TYPE}, "Used to get shared preferences"), // Get shared preference methods new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getString", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, String.class}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getStringSet", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, Set.class}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getAll", new Intro_GET_ALL_SHARED_PREF(), new Class<?>[]{}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getBoolean", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, Boolean.TYPE}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getFloat", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, Float.TYPE}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getInt", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, Integer.TYPE}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "getLong", new Intro_GET_SHARED_PREF(), new Class<?>[]{String.class, Long.TYPE}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.app.SharedPreferencesImpl", "contains", new Intro_CONTAINS_SHARED_PREF(), new Class<?>[]{String.class}, "Checks whether the preferences contains a preference"), new HookConfig(true, "STORAGE", "PREF", "android.content.SharedPreferences.Editor", "putString", new Intro_PUT_SHARED_PREF(), new Class<?>[]{String.class, String.class}, "Set a String value in the preferences editor, to be written back once"), new HookConfig(true, "STORAGE", "PREF", "android.content.SharedPreferences.Editor", "putBoolean", new Intro_PUT_SHARED_PREF(), new Class<?>[]{String.class, Boolean.TYPE}, "Set a bool value in the preferences editor, to be written back once"), new HookConfig(true, "STORAGE", "PREF", "android.content.SharedPreferences.Editor", "putInt", new Intro_PUT_SHARED_PREF(), new Class<?>[]{String.class, Integer.TYPE}, "Set an Int value in the preferences editor, to be written back once"), new HookConfig(false, "STORAGE", "PREF", "android.content.SharedPreferences.Editor", "commit", new Intro_DUMP(), new Class<?>[]{}, "Used to commit shared preferences"), /* ############################################ * ############### URI Methods */ new HookConfig(true, "IPC", "URI", "android.content.ContextWrapper", "grantUriPermission", new Intro_DUMP(), new Class<?>[]{String.class, Uri.class, Integer.TYPE}, "Grant permission to access a specific Uri to another package"), // used to register URI for a content provider new HookConfig(false, "IPC", "URI", "android.content.UriMatcher", "addURI", new Intro_URI_REGISTER(), new Class<?>[]{String.class, String.class, Integer.TYPE}, "Add a URI to match, and the code to return when this URI is matched."), /* ############################################ * ############### SSL Methods */ new HookConfig(true, "CRYPTO", "SSL", "org.apache.http.conn.ssl.SSLSocketFactory", "connectSocket", new Intro_DUMP(), new Class<?>[]{Socket.class, String.class, Integer.TYPE, InetAddress.class, Integer.TYPE, HttpParams.class}, "Connects a socket to the given host (uses SSL)"), new HookConfig(true, "CRYPTO", "SSL", "org.apache.http.conn.ssl.SocketFactory", "connectSocket", new Intro_DUMP(), new Class<?>[]{Socket.class, String.class, Integer.TYPE, InetAddress.class, Integer.TYPE, HttpParams.class}, "Connects a socket to the given host"), new HookConfig(true, "CRYPTO", "SSL", "org.apache.http.client.methods.HttpGet", "HttpGet", new Intro_CHECK_URI(), new Class<?>[]{String.class}, "HTTP GET"), //new HookConfig(false, "CRYPTO", "SSL", "org.apache.http.client.methods.HttpGet", "HttpGet", // new Intro_DUMP(), new Class<?>[]{URI.class}, "HTTP GET"), //new HookConfig(false, "CRYPTO", "SSL", "org.apache.http.client.methods.HttpPost", "HttpPost", // new Intro_DUMP(), new Class<?>[]{URI.class}, "HTTP POST"), new HookConfig(true, "CRYPTO", "SSL", "org.apache.http.client.methods.HttpPost", "HttpPost", new Intro_CHECK_URI(), new Class<?>[]{String.class}, "HTTP POST"), // Hooks methods used to do cert pinning or remove cert validation new HookConfig(true, "CRYPTO", "SSL", "javax.net.ssl.SSLContext", "init", new Intro_SSL_CHECK_TRUST_MANAGER(), new Class<?>[]{KeyManager[].class, TrustManager[].class, SecureRandom.class}, ""), new HookConfig(true, "CRYPTO", "SSL", "javax.net.ssl.HttpsURLConnection", "setSSLSocketFactory", new Intro_SSL_CHECK_TRUST_SOCKETFACTORY(), new Class<?>[]{javax.net.ssl.SSLSocketFactory.class}, ""), // these methods can be used to allow all hostnames to be used new HookConfig(true, "CRYPTO", "SSL", "org.apache.http.conn.ssl.SSLSocketFactory", "setHostnameVerifier", new Intro_CHECK_HOSTNAME_VERIFIER(), new Class<?>[]{X509HostnameVerifier.class}, ""), new HookConfig(true, "CRYPTO", "SSL", "javax.net.ssl.HttpsURLConnection", "setDefaultHostnameVerifier", new Intro_CHECK_HOSTNAME_VERIFIER(), new Class<?>[]{HostnameVerifier.class}, ""), /* ############################################ * ############### WEBVIEW Methods */ new HookConfig(true, "MISC", "WEBVIEW", "android.webkit.WebSettings", "setJavaScriptEnabled", new Intro_WEBVIEW_SET(), new Class<?>[]{Boolean.TYPE}, "Tells the WebView to enable JavaScript execution"), // deprecated new HookConfig(false, "MISC", "WEBVIEW", "android.webkit.WebSettings", "setPluginState", new Intro_WEBVIEW_SET(), new Class<?>[]{Boolean.TYPE}, "Tells the WebView to enable Plugin execution (deprecated in API 18)"), new HookConfig(true, "MISC", "WEBVIEW", "android.webkit.WebSettings", "setAllowFileAccess", new Intro_WEBVIEW_SET(), new Class<?>[]{Boolean.TYPE}, "Tells the WebView to enable FileSystem access"), // can lead to RCE if Android <= JELLY_BEAN (v17?) new HookConfig(true, "MISC", "WEBVIEW", "android.webkit.WebView", "addJavascriptInterface", new Intro_WEBVIEW_JS_BRIDGE(), new Class<?>[]{Object.class, String.class}, "Injects the supplied Java object into this WebView."), // This is a powerful feature, but also presents a security risk for applications // targeted to API level JELLY_BEAN or below, because JavaScript could use // reflection to access an injected object's public fields. /* ############################################ * ############### SQLite Methods */ // prone to SQLi new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "execSQL", new Intro_ExecSQL(), new Class<?>[]{String.class}, "Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "execSQL", new Intro_ExecSQL(), new Class<?>[]{String.class, Object[].class}, "Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "update", new Intro_SQLite_UPDATE(), new Class<?>[]{String.class, ContentValues.class, String.class, String[].class}, "Convenience method for updating rows in the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "updateWithOnConflict", new Intro_SQLite_UPDATE(), new Class<?>[]{String.class, ContentValues.class, String.class, String[].class, Integer.TYPE}, "Convenience method for updating rows in the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "insert", new Intro_SQLite_INSERT(), new Class<?>[]{String.class, String.class, ContentValues.class}, "Convenience method for inserting a row into the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "insertOrThrow", new Intro_SQLite_INSERT(), new Class<?>[]{String.class, String.class, ContentValues.class}, "Convenience method for inserting a row into the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "insertWithOnConflict", new Intro_SQLite_INSERT(), new Class<?>[]{String.class, String.class, ContentValues.class, Integer.TYPE}, "Convenience method for inserting a row into the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "replace", new Intro_SQLite_INSERT(), new Class<?>[]{String.class, String.class, ContentValues.class}, "Convenience method for inserting a row into the database."), new HookConfig(true, "STORAGE", "SQLite", "android.database.sqlite.SQLiteDatabase", "replace", new Intro_SQLite_INSERT(), new Class<?>[]{String.class, String.class, ContentValues.class}, "Convenience method for inserting a row into the database."), }; }